package com.example.rbac.config;
import com.example.rbac.handler.MyAuthenticationFailHandler;
import com.example.rbac.handler.MyAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import javax.annotation.Resource;
import javax.sql.DataSource;
//注解表明这是一个配置类
@Configuration
// @EnableWebSecurity 注解：1：加载了WebSecurityConfiguration配置类, 配置安全认证策略。
//2：加载了AuthenticationConfiguration, 配置了认证信息。
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private SysSecurityService sysSecurityService;
    //实体类注入
    @Resource
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Resource
    private MyAuthenticationFailHandler myAuthenticationFailHandler;
    @Autowired
    private DataSource dataSource;
    //http 配置
    /*
      *antMatcher 匹配的具体请求路径
      *formLogin 开启表单登录认证 默认是使用自带的登录页面
      *loginPage  配置自定义登录页
      *logout  退出登录
      *logoutUrl 自定义退出登录的url
      *logoutSuccessUrl  自定义退出登录成功的url
    */
    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http.antMatcher("/admin/**")
                .formLogin()
                .loginPage("/admin/login")
                .successHandler(myAuthenticationSuccessHandler)
                .failureHandler(myAuthenticationFailHandler)
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/admin/login");
        //认证权限
        /*
          *antMatchers 匹配的具体请求路径
          *permitAll 允许所有用户访问
        */
        http.authorizeRequests()
                .antMatchers("/admin/login")
                .permitAll()
                //rbac 访问admin/rbac的时候，使用自定义hasPermission验证是否允许访问
                 .antMatchers("/admin/list","/admin/add","/admin/del")
                .access("@rbacService.hasPermission(request,authentication)");
        //记住我
        http.rememberMe()
                //生成token的时候会使用，对密码进行加密解密处理
                .key("shengmengyu")
                .tokenRepository(new JdbcTokenRepositoryImpl())
                //配置自动登录过期时间  默认过期时间是两周
                .tokenValiditySeconds(24*60*60);
        //csrf忽略的请求配置
        //http.csrf().ignoringAntMatchers("");
        //关闭csrf
        http.csrf().disable();
    }
    //认证配置
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(sysSecurityService)
                .passwordEncoder(new BCryptPasswordEncoder());
    }
    //密码编译器
    @Bean
    BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    //remember_me 中，jdbc持久化操作
    @Autowired
    JdbcTokenRepositoryImpl tokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository=new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        //自动创建保存token持久化的表
        tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }
}
